//----------------------------------------------------------------------------
// Anti-Grain Geometry - Version 2.4
// Copyright (C) 2007 Lars Brubaker
//                  larsbrubaker@gmail.com
//
// Permission to copy, use, modify, sell and distribute this software 
// is granted provided this copyright notice appears in all copies. 
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// classes ButtonWidget
//
//----------------------------------------------------------------------------
using System;
using AGG;
using AGG.VertexSource;
using AGG.Transform;
using AGG.Image;

namespace AGG.UI
{
    public abstract class GUIButtonView_Abstract
    {
        public abstract void AttachToWidget(GUIWidget widget);

        public virtual void DoDrawBeforeChildren(Graphics2D graphics2D, ButtonWidget widget)
        {
        }

        public virtual void DoDrawAfterChildren(Graphics2D graphics2D, ButtonWidget widget)
        {
        }

        public virtual string Text 
        { 
            get 
            {
                return "";
            }

            set
            {
            }
        }
    };

    public abstract class TextLable_ButtonView : GUIButtonView_Abstract
    {
        protected TextWidget buttonText;
        double textPadding;

        public double TextPadding { get { return textPadding; } set { textPadding = value; } }

        public TextLable_ButtonView(string lable)
            : this(lable, 16, 0)
        {

        }

        public TextLable_ButtonView(string lable, double textHeight, double textPadding)
        {
            buttonText = new TextWidget(lable, textHeight);
            TextPadding = textPadding;
        }

        public override void AttachToWidget(GUIWidget widget)
        {
            widget.AddChild(buttonText);

            double totalExtra = TextPadding;
            rect_d bounds = new rect_d(-totalExtra, -totalExtra, +buttonText.Width + totalExtra, +buttonText.Height + totalExtra);
            widget.Bounds = bounds;

            widget.MouseEnter += redrawButtonIfRequired;
            widget.MouseDown += redrawButtonIfRequired;
            widget.MouseUp += redrawButtonIfRequired;
            widget.MouseLeave += redrawButtonIfRequired;

            // center the text in the button
            buttonText.Transform = Affine.NewTranslation(0, -buttonText.Printer.TypeFaceStyle.DescentInPixels);
        }

        public override string Text
        {
            get
            {
                return buttonText.Text;
            }
            set
            {
                buttonText.Text = value;
            }
        }

        public void redrawButtonIfRequired(object sender, EventArgs e)
        {
            ((GUIWidget)sender).Invalidate();
        }
    };

    public class ThreeImageButtonView : GUIButtonView_Abstract
    {
        IImageByte m_Normal;
        IImageByte m_Hover;
        IImageByte m_Pressed;
        double hoverOpacity;
        double numSecondsToFade = .15f;
        
#if !SILVERLIGHT
        System.Diagnostics.Stopwatch timeSinceLastDraw = new System.Diagnostics.Stopwatch();
#endif

        public ThreeImageButtonView(IImageByte normal, IImageByte hover, IImageByte pressed)
        {
            hoverOpacity = 0;
            m_Normal = normal;
            m_Hover = hover;
            m_Pressed = pressed;
        }

        public override void AttachToWidget(GUIWidget widget)
        {
            widget.SetBounds(m_Normal.GetBounds());

            widget.MouseEnter += redrawButtonIfRequired;
            widget.MouseDown += redrawButtonIfRequired;
            widget.MouseUp += redrawButtonIfRequired;
            widget.MouseLeave += redrawButtonIfRequired;
        }

        public void redrawButtonIfRequired(object sender, EventArgs e)
        {
            ((GUIWidget)sender).Invalidate();
        }

        public override void DoDrawBeforeChildren(Graphics2D graphics2D, ButtonWidget widget)
        {
#if SILVERLIGHT
                    throw new NotImplementedException();
#else
            double numSecondsSinceLastDraw = timeSinceLastDraw.Elapsed.TotalSeconds;
            timeSinceLastDraw.Reset();
            timeSinceLastDraw.Start();
#endif

            double x = 0;
            double y = 0;

            if (widget.MouseOverWidget)
            {
                if (widget.MouseDownOnButton)
                {
                    graphics2D.Render(m_Pressed, x, y);
                }
                else
                {
                    if (hoverOpacity < 1)
                    {
                        graphics2D.Render(m_Normal, x, y);
                    }
                    graphics2D.Render(m_Hover, x, y, new RGBA_Bytes(1, 1, 1, hoverOpacity), Graphics2D.BlendMode.FORCE_SOURC_ONE_DEST_ONE_MINUS_ALPHA_BLENDER);
                }

#if SILVERLIGHT
                    throw new NotImplementedException();
#else
                hoverOpacity += numSecondsSinceLastDraw / numSecondsToFade;
#endif
                if (hoverOpacity > 1) hoverOpacity = 1;
            }
            else
            {
                graphics2D.Render(m_Normal, x, y);
                if (hoverOpacity > 0)
                {
                    graphics2D.Render(m_Hover, x, y, new RGBA_Bytes(1, 1, 1, hoverOpacity), Graphics2D.BlendMode.FORCE_SOURC_ONE_DEST_ONE_MINUS_ALPHA_BLENDER);
                }
#if SILVERLIGHT
                    throw new NotImplementedException();
#else
                hoverOpacity -= numSecondsSinceLastDraw / numSecondsToFade;
#endif
                if (hoverOpacity < 0) hoverOpacity = 0;
            }

            base.DoDrawBeforeChildren(graphics2D, widget);
        }

        public override void DoDrawAfterChildren(Graphics2D graphics2D, ButtonWidget widget)
        {
            base.DoDrawAfterChildren(graphics2D, widget);
        }
    };

    public class SimpleVector_ButtonView : TextLable_ButtonView
    {
        double m_BorderWidth;
        double m_BorderRadius;

        public double BorderWidth { get { return m_BorderWidth; } set { m_BorderWidth = value; } }
        public double BorderRadius { get { return m_BorderRadius; } set { m_BorderRadius = value; } }

        public SimpleVector_ButtonView(string lable)
            : this(lable, 16, 3, 3, 5)
        {
        }

        public SimpleVector_ButtonView(string lable, double textHeight, double textPadding, double borderWidth, double borderRadius)
            : base(lable, textHeight, textPadding)
        {
            BorderRadius = borderRadius;
            m_BorderWidth = borderWidth;
        }

        public override void AttachToWidget(GUIWidget widget)
        {
            base.AttachToWidget(widget);

            double totalExtra = BorderWidth + TextPadding;
            rect_d bounds = new rect_d(-totalExtra, -totalExtra, +buttonText.Width + totalExtra, +buttonText.Height + totalExtra);
            widget.Bounds = bounds;
        }

        public override void DoDrawBeforeChildren(Graphics2D graphics2D, ButtonWidget widget)
        {
            double totalExtra = BorderWidth + TextPadding;
            rect_d Bounds = new rect_d(-totalExtra, -totalExtra, buttonText.Width + totalExtra, buttonText.Height + totalExtra);
            RoundedRect rectBorder = new RoundedRect(Bounds, BorderRadius);
            graphics2D.Render(rectBorder, new RGBA_Bytes(0, 0, 0));
            rect_d insideBounds = Bounds;
            insideBounds.Inflate(-BorderWidth);
            RoundedRect rectInside = new RoundedRect(insideBounds, Math.Max(BorderRadius - BorderWidth, 0));
            RGBA_Bytes insideColor = new RGBA_Bytes(1.0, 1.0, 1.0);
            if (widget.MouseOverWidget)
            {
                if (widget.MouseDownOnButton)
                {
                    insideColor = new RGBA_Bytes(255, 110, 110);
                }
                else
                {
                    insideColor = new RGBA_Bytes(225, 225, 255);
                }
            }

            graphics2D.Render(rectInside, insideColor);
        }
    }

    public class ButtonWidget : GUIWidget
    {
        GUIButtonView_Abstract buttonView;

		bool m_MouseDownOnButton = false;

        public delegate void ButtonEventHandler(object sender, MouseEventArgs mouseEvent);
		public event ButtonEventHandler Click;

        public bool MouseDownOnButton
		{
			get { return m_MouseDownOnButton; }
			set { m_MouseDownOnButton = value; }
		}

        public ButtonWidget()
            : this(0, 0, "None")
        {
        }

        public ButtonWidget(double x, double y, GUIButtonView_Abstract buttonView)
        {
            Transform = Affine.NewTranslation(x, y);

            this.buttonView = buttonView;
            this.buttonView.AttachToWidget(this);
        }

        public ButtonWidget(double x, double y, String buttonText)
            : this(x, y, new SimpleVector_ButtonView(buttonText))
        {
            
        }

        public void ClickButton(MouseEventArgs mouseEvent)
        {
            if (Click != null)
            {
                Click(this, mouseEvent);
            }
        }

        public enum Alignment { Center, Left, Right };

        public void AlignX(double x, Alignment alignment)
        {
            Affine transform = Transform;
            switch (alignment)
            {
                case Alignment.Center:
                    Transform = Affine.NewTranslation(x - Width / 2, transform.ty);
                    break;

                case Alignment.Left:
                    Transform = Affine.NewTranslation(x, transform.ty);
                    break;
                
                case Alignment.Right:
                    Transform = Affine.NewTranslation(x - Width, transform.ty);
                    break;
            }
        }

        public override void OnDraw(Graphics2D graphics2D)
        {
            buttonView.DoDrawBeforeChildren(graphics2D, this);
            base.OnDraw(graphics2D);
            buttonView.DoDrawAfterChildren(graphics2D, this);
        }

        public override string Text
        {
            get
            {
                return buttonView.Text;
            }
            set
            {
                buttonView.Text = value;
            }
        }
          
        override public void OnMouseDown(MouseEventArgs mouseEvent)
        {
            if(InRect(mouseEvent.X, mouseEvent.Y))
            {
            	MouseDownOnButton = true;
            }
            else
            {
            	MouseDownOnButton = false;
            }

            base.OnMouseDown(mouseEvent);
        }

        override public void OnMouseUp(MouseEventArgs mouseEvent)
        {
        	if(MouseDownOnButton
        	  && InRect(mouseEvent.X, mouseEvent.Y))
        	{
                ClickButton(mouseEvent);
        	}

        	MouseDownOnButton = false;

            base.OnMouseUp(mouseEvent);
        }

        override public void OnKeyDown(KeyEventArgs keyEvent)
        {
            if(keyEvent.KeyCode == Keys.Space)
            {
            	if(Click != null)
            	{
            		Click(this, null);
            	}
                keyEvent.Handled = true;
            }
        }
    };
}
